package com.king.juc.atomicdemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.*;

/**
 * @author king
 * @date 2020/11/29 19:33
 */
public class AtomicApi {
    public static void main(String[] args) {
        // 原子整数类型
//        AtomicInteger a = new AtomicInteger(10);

//        addAndLess(a);
//        multiplyAndDivide(a);

        // 普通数组
        demo(
                () -> new int[10],
                (array) -> array.length,
                (array, index) -> array[index]++,
                array -> System.out.println(Arrays.toString(array))
        );

        // AtomicIntegerArray
        demo(
                () -> new AtomicIntegerArray(10),
                AtomicIntegerArray::length,
                AtomicIntegerArray::getAndIncrement,
                System.out::println
        );
    }

    /**
     * 加减操作
     *
     * @param a AtomicInteger
     */
    private static void addAndLess(AtomicInteger a) {
        // 相当于 ++a
        System.out.println(a.incrementAndGet());
        // 相当于 a++
        System.out.println(a.getAndIncrement());

        System.out.println(a.get());

        // 获取再增加
        System.out.println(a.getAndAdd(5));
        // 增加再获取
        System.out.println(a.addAndGet(5));

        System.out.println(a.get());
    }

    /**
     * 乘除操作
     *
     * @param a AtomicInteger
     */
    private static void multiplyAndDivide(AtomicInteger a) {
        // 乘法
//        a.updateAndGet(x -> x * 10);
        updateAndGet(a, x -> x * 10);

        System.out.println(a.get());
    }

    /**
     * 实现updateAndGet()方法
     *
     * @param a        AtomicInteger
     * @param operator 提供一个接口, 具体逻辑由该接口实现类完成
     */
    private static void updateAndGet(AtomicInteger a, IntUnaryOperator operator) {
        while (true) {
            int prev = a.get();
            // 调用 operator.applyAsInt() 得到返回值, 具体逻辑由传入的 lambda 表达式实现
            int next = operator.applyAsInt(prev);
            if (a.compareAndSet(prev, next)) {
                break;
            }
        }
    }

    /**
     * @param arraySupplier 提供数组, 可以是现成不安全数组或者线程安全数组
     *                      suplier 提供者 无中生有 () -> 结果
     * @param lengthFun     获取数组长度的方法
     *                      function 函数 一个参数一个结果 (参数) -> 结果, BiFunction(参数1, 参数2) -> 结果
     * @param putConsumer   自增方法, 回传 array, index
     * @param printConsumer 打印数组的方法
     *                      consumer 消费者 一个参数没有结果 (参数) -> () BiConsumer(参数1, 参数2) -> ()
     * @param <T>
     */
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFun,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer) {
        List<Thread> ts = new ArrayList<>();
        T array = arraySupplier.get();
        int length = lengthFun.apply(array);
        for (int i = 0; i < length; i++) {
            // 每个线程对数组操作10000次
            ts.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }

        // 启动线程
        ts.forEach(t -> t.start());
        // 待定所有线程结束
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        printConsumer.accept(array);
    }
}
